package labox.innovation.gameserver.model.actor.instance;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import labox.innovation.config.Config;
import labox.innovation.gameserver.datatables.SkillTable;
import labox.innovation.gameserver.model.L2Object;
import labox.innovation.gameserver.model.L2Skill;
import labox.innovation.gameserver.model.actor.L2Character;
import labox.innovation.gameserver.model.actor.L2Summon; //import labox.innovation.gameserver.network.serverpackets.SetSummonRemainTime;
import labox.innovation.gameserver.skills.l2skills.L2SkillSummon;
import labox.innovation.gameserver.templates.chars.NpcTemplate;
import labox.innovation.gameserver.timer.Timer;

public class L2SummonInstance extends L2Summon {

	protected static final Logger log = LoggerFactory.getLogger(L2SummonInstance.class.getName());

	private float _expPenalty = 0; // exp decrease multiplier (i.e. 0.3 (= 30%) for shadow)

	/**
	 * 需要消耗的道具ID
	 */
	private int _itemConsumeId;

	/**
	 * 需要消耗的道具数量
	 */
	private int _itemConsumeCount;

	private int _itemConsumeSteps;

	/**
	 * 召唤物整体的生命周期
	 */
	private final int _totalLifeTime;

	private final int _timeLostIdle;

	private final int _timeLostActive;

	/**
	 * 召唤物剩余的存活时间
	 */
	private int _timeRemaining;

	private int _nextItemConsumeTime;

	public int lastShowntimeRemaining; // Following FbiAgent's example to avoid sending useless packets

	/**
	 * 召唤物的生命周期定时器
	 */
	private Timer _summonLifeTask;

	public L2SummonInstance(long objectId, NpcTemplate template, FuzePcInstance owner, L2Skill skill) {
		super(objectId, template, owner);

		if (skill != null) {
			final L2SkillSummon summonSkill = (L2SkillSummon) skill;
			_itemConsumeId = summonSkill.getItemConsumeIdOT();
			_itemConsumeCount = summonSkill.getItemConsumeOT();
			_itemConsumeSteps = summonSkill.getItemConsumeSteps();
			_totalLifeTime = summonSkill.getTotalLifeTime();
			_timeLostIdle = summonSkill.getTimeLostIdle();
			_timeLostActive = summonSkill.getTimeLostActive();
		} else {
			// defaults
			_itemConsumeId = 0;
			_itemConsumeCount = 0;
			_itemConsumeSteps = 0;
			_totalLifeTime = 1200000; // 20 minutes
			_timeLostIdle = 1000;
			_timeLostActive = 1000;
		}
		_timeRemaining = _totalLifeTime;
		lastShowntimeRemaining = _totalLifeTime;

		if (_itemConsumeId == 0)
			_nextItemConsumeTime = -1; // do not consume
		else if (_itemConsumeSteps == 0)
			_nextItemConsumeTime = -1; // do not consume
		else
			_nextItemConsumeTime = _totalLifeTime - _totalLifeTime / (_itemConsumeSteps + 1);

		// When no item consume is defined task only need to check when summon life time has ended.
		// Otherwise have to destroy items from owner's inventory in order to let summon live.
		int delay = 1000;

		if (_log.isDebugEnabled() && (_itemConsumeCount != 0))
			_log.warn("L2SummonInstance: Item Consume ID: " + _itemConsumeId + ", Count: " + _itemConsumeCount + ", Rate: " + _itemConsumeSteps + " times.");
		if (_log.isDebugEnabled())
			_log.warn("L2SummonInstance: Task Delay " + (delay / 1000) + " seconds.");

		_summonLifeTask = new Timer(delay, true, new SummonLifetime(getOwner(), this));
		_summonLifeTask.start();

	}

	@Override
	public final int getLevel() {
		return (getTemplate() != null ? getTemplate().level : 0);
	}

	@Override
	public int getSummonType() {
		return 1;
	}

	public void setExpPenalty(float expPenalty) {
		_expPenalty = expPenalty;
	}

	public float getExpPenalty() {
		return _expPenalty;
	}

	/**
	 * 需要消耗的道具数量
	 * 
	 * @return
	 */
	public int getItemConsumeCount() {
		return _itemConsumeCount;
	}

	/**
	 * 需要消耗的道具ID
	 * 
	 * @return
	 */
	public int getItemConsumeId() {
		return _itemConsumeId;
	}

	public int getItemConsumeSteps() {
		return _itemConsumeSteps;
	}

	public int getNextItemConsumeTime() {
		return _nextItemConsumeTime;
	}

	/**
	 * 召唤物整体的生命周期
	 * @return
	 */
	public int getTotalLifeTime() {
		return _totalLifeTime;
	}

	public int getTimeLostIdle() {
		return _timeLostIdle;
	}

	public int getTimeLostActive() {
		return _timeLostActive;
	}

	/**
	 * 召唤物剩余的存活时间
	 * @return
	 */
	public int getTimeRemaining() {
		return _timeRemaining;
	}

	public void setNextItemConsumeTime(int value) {
		_nextItemConsumeTime = value;
	}

	public void decNextItemConsumeTime(int value) {
		_nextItemConsumeTime -= value;
	}

	public void decTimeRemaining(int value) {
		_timeRemaining -= value;
	}

	public void addExp(int addToExp) {
		getOwner().addExp(addToExp);
	}

	@Override
	public boolean doDie(L2Character killer) {
		if (!super.doDie(killer))
			return false;

		if (_log.isDebugEnabled())
			_log.warn("L2SummonInstance: " + getTemplate().name + " (" + getOwner().getName() + ") has been killed.");

		if (_summonLifeTask != null) {
			_summonLifeTask.cancel();
			_summonLifeTask = null;
		}
		return true;

	}

	/**
	 * Servitors' skills automatically change their level based on the servitor's level. Until level 70, the servitor gets 1 lv of skill per 10 levels. After that, it is 1 skill level per 5 servitor levels. If the resulting skill level doesn't exist use the max that does exist!
	 * 
	 * @see labox.innovation.gameserver.model.actor.L2Character#doCast(labox.innovation.gameserver.model.L2Skill)
	 */
	@Override
	public void doCast(L2Skill skill) {
		final int petLevel = getLevel();
		int skillLevel = petLevel / 10;
		if (petLevel >= 70)
			skillLevel += (petLevel - 65) / 10;

		// adjust the level for servitors less than lv 10
		if (skillLevel < 1)
			skillLevel = 1;

		L2Skill skillToCast = SkillTable.getInstance().getInfo(skill.getId(), skillLevel);

		if (skillToCast != null)
			super.doCast(skillToCast);
		else
			super.doCast(skill);
	}

	private static class SummonLifetime implements Runnable {
		/**
		 * 召唤兽的主人
		 */
		private FuzePcInstance _activeChar;

		/**
		 * 召唤兽对象
		 */
		private L2SummonInstance _summon;

		SummonLifetime(FuzePcInstance activeChar, L2SummonInstance newpet) {
			_activeChar = activeChar;
			_summon = newpet;
		}

		public void run() {
			if (Config.DEBUG)
				log.warn("L2SummonInstance: " + _summon.getTemplate().name + " (" + _activeChar.getName() + ") run task.");

			try {
				int oldTimeRemaining = _summon.getTimeRemaining();
				int maxTime = _summon.getTotalLifeTime();
				int newTimeRemaining;

				// 如果召唤物正在攻击中
				if (_summon.isAttackingNow()) {
					_summon.decTimeRemaining(_summon.getTimeLostActive());
				} else {
					_summon.decTimeRemaining(_summon.getTimeLostIdle());
				}
				newTimeRemaining = _summon.getTimeRemaining();
				// check if the summon's lifetime has ran out
				if (newTimeRemaining < 0) {
					_summon.unSummon(_activeChar);
				}
				// check if it is time to consume another item
				else if ((newTimeRemaining <= _summon.getNextItemConsumeTime()) && (oldTimeRemaining > _summon.getNextItemConsumeTime())) {
					_summon.decNextItemConsumeTime(maxTime / (_summon.getItemConsumeSteps() + 1));

					// check if owner has enought itemConsume, if requested
					if (_summon.getItemConsumeCount() > 0 && _summon.getItemConsumeId() != 0 && !_summon.isDead() && !_summon.destroyItemByItemId("Consume", _summon.getItemConsumeId(), _summon.getItemConsumeCount(), _activeChar, true)) {
						_summon.unSummon(_activeChar);
					}
				}

				// prevent useless packet-sending when the difference isn't visible.
				if ((_summon.lastShowntimeRemaining - newTimeRemaining) > maxTime / 352) {
					//					_summon.getOwner().sendPacket(new SetSummonRemainTime(maxTime, (int) newTimeRemaining));
					_summon.lastShowntimeRemaining = (int) newTimeRemaining;
				}
			} catch (Exception e) {
				log.error("Error on player [" + _activeChar.getName() + "] summon item consume task.", _activeChar.getObjectId(), e);
			}
		}
	}

	@Override
	public void unSummon(FuzePcInstance owner) {
		if (_log.isDebugEnabled())
			_log.warn("L2SummonInstance: " + getTemplate().name + " (" + owner.getName() + ") unsummoned.");

		if (_summonLifeTask != null) {
			_summonLifeTask.cancel();
			_summonLifeTask = null;
		}

		super.unSummon(owner);
	}

	//	@Override
	public boolean destroyItem(String process, int objectId, int count, L2Object reference, boolean sendMessage) {
		return getOwner().destroyItem(process, objectId, count, reference, sendMessage);
	}

	@Override
	public boolean destroyItemByItemId(String process, int itemId, int count, L2Object reference, boolean sendMessage) {
		if (_log.isDebugEnabled())
			_log.warn("L2SummonInstance: " + getTemplate().name + " (" + getOwner().getName() + ") consume.");

		return getOwner().destroyItemByItemId(process, itemId, count, reference, sendMessage);
	}
}
